/*	This file is part of LSAC.

	LSAC is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	LSAC is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with LSAC.  If not, see <http://www.gnu.org/licenses/>.

	Copyright (c) 2010 LEPESME "Jiboo" Jean-Baptiste
*/

#include "cFunction.h"
#include "lsac.h"
#include "cInstReturn.h"
#include "cCPPUtils.h"

cFunction::cFunction(cLocation pLocation, eType pType, string pName)
	: cBlock(pLocation, NULL)
{
	this->dType = pType;
	this->dName = pName;
}

cFunction::~cFunction()
{
	list<cInstDecl*>::iterator lIterator = this->dParams.begin();
	for(; lIterator != this->dParams.end(); lIterator++)
	{
		delete (*lIterator);
	}
}

void cFunction::print(int pLevel)
{
	PRINT_LOG("cFunction " << this << " " << this->dType << " " << this->dName);
	PRINT_LOG("Params:");
	list<cInstDecl*>::iterator lIterator = this->dParams.begin();
	for(; lIterator != this->dParams.end(); lIterator++)
	{
		(*lIterator)->print(pLevel + 1);
	}
	cBlock::print_statements(pLevel);
}

void cFunction::validate(cSemContext *pContext)
{
	if(pContext->funcExists(this->dName)) ERROR("Erreur en " << this->dLocation << " fonction " << this->dName << " d�ja d�clar�.");

	if(this->dName == "main") ERROR("Erreur en " << this->dLocation << " le nom de fonction main est reservé.");

	if(this->dType != TYPE_VOID)
	{
		bool lFound = false;
		std::list<cStatement*>::iterator lIterator = this->dStatements.begin();
		for(; lIterator != this->dStatements.end(); lIterator++)
		{
			if(typeid(*(*lIterator)) == typeid(cInstReturn))
			{
				lFound = true;
			}
		}

		if(!lFound) ERROR("Erreur en " << this->dLocation << ", fonction retournant un '" << this->dType << "' mais aucun 'retourne' trouve.");
	}

	pContext->declareFunction(this);

	list<cInstDecl*>::iterator lIterator = this->dParams.begin();
	for(; lIterator != this->dParams.end(); lIterator++)
	{
		(*lIterator)->validate(pContext);
		pContext->declareVar(*lIterator);
	}

	this->validate_statements(pContext);
	pContext->removeLocals(this);
}

void cFunction::genCode(ostream &pStream)
{
	pStream << cCPPUtils::getType(this->dType) << " " << this->dName << "(";
	list<cInstDecl*>::iterator lIterator = this->dParams.begin();
	for(; lIterator != this->dParams.end(); lIterator++)
	{
		pStream << cCPPUtils::getType((*lIterator)->dType) << " " << (*lIterator)->dLValue;
		if(*lIterator != this->dParams.back())
		{
			pStream << ", ";
		}
	}
	pStream << ")" << endl << "{" << endl;
	this->gen_statements(pStream);
	pStream << "}" << endl;
}
